package database

import (
	"go-redis/aof"
	"go-redis/config"
	"go-redis/interface/resp"
	"go-redis/lib/logger"
	"go-redis/resp/reply"
	"strconv"
	"strings"
)

//StandaloneDatabase 定义Redis数据库对象
type StandaloneDatabase struct {
	dbSet []*DB
	// aof的处理函数
	aofHandler *aof.AofHandler
}

//NewStandaloneDatabase 创建数据库的实例
func NewStandaloneDatabase() *StandaloneDatabase {
	mdb := &StandaloneDatabase{}
	if config.Properties.Databases == 0 {
		config.Properties.Databases = 16
	}
	mdb.dbSet = make([]*DB, config.Properties.Databases)
	for i, _ := range mdb.dbSet {
		singleDB := MakeDB()
		singleDB.index = i
		mdb.dbSet[i] = singleDB
	}
	// aof的初始化
	if config.Properties.AppendOnly {
		handler, err := aof.NewAofHandler(mdb)
		if err != nil {
			panic(err)
		}
		mdb.aofHandler = handler
		for _, db := range mdb.dbSet {
			currentDB := db
			currentDB.addAof = func(cmdLine CmdLine) {
				mdb.aofHandler.AddAof(currentDB.index, cmdLine)
			}
		}
	}
	return mdb
}

func (mdb *StandaloneDatabase) Exec(conn resp.Connection, cmdLine [][]byte) resp.Reply {
	defer func() {
		if err := recover(); err != nil {
			logger.Error(err)
		}
	}()
	// 执行业务逻辑的方法
	// 获取执行的命令
	cmdName := strings.ToLower(string(cmdLine[0]))
	if cmdName == "select" {
		if len(cmdLine) != 2 {
			return reply.MakeArgNumErrReply("select")
		}
		return execSelect(conn, mdb, cmdLine)
	}
	// 获取客户端连接的数据库的index
	dbIndex := conn.GetDBIndex()
	db := mdb.dbSet[dbIndex]
	return db.Exec(conn, cmdLine)
}

func (d *StandaloneDatabase) AfterClientClose(conn resp.Connection) {}

func (d *StandaloneDatabase) Close() {}

// 客户端执行切换数据库的操作
func execSelect(c resp.Connection, mdb *StandaloneDatabase, args [][]byte) resp.Reply {
	dbIndex, err := strconv.Atoi(string(args[0]))
	if err != nil {
		return reply.MakeErrReply("ERR invalid DB index")
	}
	if dbIndex >= len(mdb.dbSet) {
		return reply.MakeErrReply("ERR DB index is out of range")
	}
	c.SelectDB(dbIndex)
	return reply.MakeOkReply()
}
